package controllers;

import java.util.List;

import play.mvc.Controller;

import models.User;

import models.Plan;
import models.PlanRating;

public class Plans extends Controller{


	
	/**
	 * it's the method called from the View of the planRating UI.
	 * 
	 * @param rating
	 *            the rating chosen by the user
	 * @param planId
	 *            the id of the rated plan
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static void rateplan(int rating, long planId) {
		String userName = session.get("username");
		notFoundIfNull(userName);

		validation.range(rating, 1, 5);
		validation.range(planId, 1, Plan.count());
		if (validation.hasErrors()) {
			notFound("Error with id of the plan or the rating range");
		}

		User user = User.getUserInfo(userName);
		Plan plan = Plan.findById(planId);
		if (plan == null || user == null) {
			notFound();
		}

		
			addOrUpdateRating(plan, user, rating); // no data yet.
			renderText((int) plan.planRating);
	}

	
	/**
	 * the method takes a rating and the user who chose this rating and the
	 * rated plan and update the rating if the plan was already rated by this
	 * user or add the new rating if it wasn't rated by this user be4
	 * 
	 * @param plan
	 *            the plan that will be rated
	 * @param user
	 *            the rating user
	 * @param newUserRating
	 *            the new rating chosen by the user.
	 * @return true if it's new Rating. False if it's changing rating.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static boolean addOrUpdateRating(Plan plan, User user,
			int newUserRating) {
		
		user = User.findById(user.id);
		plan = Plan.findById(plan.id);
		List<PlanRating> planRatings = user.plansRatings;
		for (PlanRating planRating : planRatings) {
			if (planRating.plan.id == plan.id) { // if true then it's nt new
				double newPlanRating = calculateChangedRating(planRating,
						newUserRating); // rating

				planRating.updateRating(newUserRating, newPlanRating);// the
																		// user's
																		// rating
				return false;
			}
		}
		// the rating is new.
		new PlanRating(plan, user, newUserRating).save();
		double rating = calculateNewRating(plan, newUserRating);
		plan.updateRating(rating);// the whole value
		return true;
	}

	/**
	 * the method adds the new rating to the plan Rating.
	 * 
	 * @param plan
	 *            the rated plan.
	 * @param newRating
	 *            the new rating will be added
	 * @return returns the new rating for the plan.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static double calculateNewRating(Plan plan, int newRating) {
		int n = plan.usersRatings.size();
		return (((n - 1) * plan.planRating) + newRating) / ((n - 1) + 1);
	}

	/**
	 * the method calculates the new rating for the plan after changing one of
	 * its previous ratings
	 * 
	 * @param planRating
	 *            the planRating object that contains the rated plan, the old
	 *            rating, and the rating user.
	 * @param newRating
	 *            the new rating chose by the user
	 * @return the new calculated rating for the plan.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static double calculateChangedRating(PlanRating planRating,
			int newRating) {
		int n = planRating.plan.usersRatings.size();
		double rating = planRating.plan.planRating;
		int oldRating = planRating.rating;
		return ((n * rating) - oldRating + newRating) / n;
	}


	
}
